using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace CustomControls
{
    /// <summary>
    /// Summary description for UserControl1.
    /// </summary>
    public class CustomButton : System.Windows.Forms.Button
    {
        public enum ControlState
        {
            /// <summary>The XP control is in the normal state.</summary>
            Normal,
            /// <summary>The XP control is in the hover state.</summary>
            Hover,
            /// <summary>The XP control is in the pressed state.</summary>
            Pressed,
            /// <summary>The XP control object is in the default state.</summary>
            Default,
            /// <summary>The XP control object is in the disabled state.</summary>
            Disabled
        }		/// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        public CustomButton()
        {
            // This call is required by the Windows.Forms Form Designer.
            InitializeComponent();
            this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint |
                ControlStyles.DoubleBuffer, true);

            // TODO: Add any initialization after the InitComponent call


        }
        #region Instance fields
        private ControlState enmState = ControlState.Normal;
        private bool bCanClick = false;
        private Point locPoint;
        #endregion

        #region Properties
        public new FlatStyle FlatStyle
        {
            get { return base.FlatStyle; }
            set { base.FlatStyle = FlatStyle.Standard; }
        }

        private emunType.ColorSchema m_colorSchema = emunType.ColorSchema.Default;
        [DefaultValue("Blue"), System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)]
        public emunType.ColorSchema ColorSchema
        {
            get { return m_colorSchema; }
            set
            {
                m_colorSchema = value;
                this.Invalidate();
            }
        }

        private emunType.Shape m_Shape = emunType.Shape.BevelRectangle;
        [DefaultValue("BevelRectangle"), System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)]
        public emunType.Shape Shape
        {
            get { return m_Shape; }
            set
            {
                m_Shape = value;
                this.Invalidate();
            }
        }

        private bool m_showBorder = true;
        [DefaultValue("True"), System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)]
        public bool ShowBorder
        {
            get { return m_showBorder; }
            set
            {
                m_showBorder = value;
                this.Invalidate();
            }
        }

        public Point AdjustImageLocation
        {
            get { return locPoint; }
            set
            {
                locPoint = value;
                this.Invalidate();
            }
        }
        /// <value>Gets the clipping rectangle of the XpButton object's border.</value>
        private Rectangle BorderRectangle
        {
            get
            {
                Rectangle rc = this.ClientRectangle;
                return new Rectangle(1, 1, rc.Width - 3, rc.Height - 3);
            }
        }

        #endregion

        #region Static members
        // Fields
        private static readonly Size sizeBorderPixelIndent;
        private static readonly Color clrOuterShadow1;
        private static readonly Color clrOuterShadow2;
        private static readonly Color clrBackground1;
        private static readonly Color clrBackground2;
        private static readonly Color clrBorder;
        private static readonly Color clrInnerShadowBottom1;
        private static readonly Color clrInnerShadowBottom2;
        private static readonly Color clrInnerShadowBottom3;
        private static readonly Color clrInnerShadowRight1a;
        private static readonly Color clrInnerShadowRight1b;
        private static readonly Color clrInnerShadowRight2a;
        private static readonly Color clrInnerShadowRight2b;
        private static readonly Color clrInnerShadowBottomPressed1;
        private static readonly Color clrInnerShadowBottomPressed2;
        private static readonly Color clrInnerShadowTopPressed1;
        private static readonly Color clrInnerShadowTopPressed2;
        private static readonly Color clrInnerShadowLeftPressed1;
        private static readonly Color clrInnerShadowLeftPressed2;
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes all static fields of the XpButton class.
        /// </summary>
        static CustomButton()
        {
            // 1 pixel indent in the roundness of the border (from XP Visual Design Guidelines)
            // To make pixel indentation larger, change by a factor of 4,
            // i. e., 2 pixels indent = Size(8, 8);
            sizeBorderPixelIndent = new Size(4, 4);

            // Normal colors
            clrOuterShadow1 = Color.FromArgb(64, 164, 164, 164);
            clrOuterShadow2 = Color.FromArgb(64, Color.White);
            clrBackground1 = Color.FromArgb(250, 250, 248);
            clrBackground2 = Color.FromArgb(240, 240, 234);
            clrBorder = Color.FromArgb(0, 60, 116);
            clrInnerShadowBottom1 = Color.FromArgb(236, 235, 230);
            clrInnerShadowBottom2 = Color.FromArgb(226, 223, 214);
            clrInnerShadowBottom3 = Color.FromArgb(214, 208, 197);
            clrInnerShadowRight1a = Color.FromArgb(128, 236, 234, 230);
            clrInnerShadowRight1b = Color.FromArgb(128, 224, 220, 212);
            clrInnerShadowRight2a = Color.FromArgb(128, 234, 228, 218);
            clrInnerShadowRight2b = Color.FromArgb(128, 212, 208, 196);

            // Pressed colors
            clrInnerShadowBottomPressed1 = Color.FromArgb(234, 233, 227);
            clrInnerShadowBottomPressed2 = Color.FromArgb(242, 241, 238);
            clrInnerShadowTopPressed1 = Color.FromArgb(209, 204, 193);
            clrInnerShadowTopPressed2 = Color.FromArgb(220, 216, 207);
            clrInnerShadowLeftPressed1 = Color.FromArgb(216, 213, 203);
            clrInnerShadowLeftPressed2 = Color.FromArgb(222, 220, 211);
        }

        /// <summary>
        /// Initializes a new instance of the XpButton class.
        /// </summary>

        #endregion

        // Overridden Event Handlers
        protected override void OnClick(EventArgs ea)
        {
            this.Capture = false;
            bCanClick = false;

            if (this.ClientRectangle.Contains(this.PointToClient(Control.MousePosition)))
                enmState = ControlState.Hover;
            else
                enmState = ControlState.Normal;

            this.Invalidate();

            base.OnClick(ea);
        }
        protected override void OnMouseEnter(EventArgs ea)
        {
            base.OnMouseEnter(ea);

            enmState = ControlState.Hover;
            this.Invalidate();
        }
        protected override void OnMouseDown(MouseEventArgs mea)
        {
            base.OnMouseDown(mea);

            if (mea.Button == MouseButtons.Left)
            {
                bCanClick = true;
                enmState = ControlState.Pressed;
                this.Invalidate();
            }
        }
        protected override void OnMouseMove(MouseEventArgs mea)
        {
            base.OnMouseMove(mea);

            if (ClientRectangle.Contains(mea.X, mea.Y))
            {
                if (enmState == ControlState.Hover && this.Capture && !bCanClick)
                {
                    bCanClick = true;
                    enmState = ControlState.Pressed;
                    this.Invalidate();
                }
            }
            else
            {
                if (enmState == ControlState.Pressed)
                {
                    bCanClick = false;
                    enmState = ControlState.Hover;
                    this.Invalidate();
                }
            }
        }
        protected override void OnMouseLeave(EventArgs ea)
        {
            base.OnMouseLeave(ea);

            enmState = ControlState.Normal;
            this.Invalidate();
        }

        protected override void OnPaint(PaintEventArgs pea)
        {
            if(!Visible){ 
                base.OnPaint(pea);
                return;
            }
            switch (m_Shape)
            {
                case emunType.Shape.Default:
                    base.OnPaint(pea);
                    break;
                case emunType.Shape.Transparent:
                    OnPaintBackground(pea);
                    OnDrawTextAndImage(pea.Graphics);
                    switch (enmState)
                    {
                        case ControlState.Hover:
                        case ControlState.Pressed:
                            this.Cursor = Cursors.Hand;
                            break;
                    }
                    //if (m_showBorder) DrawBorder(pea.Graphics);
                    break;
                case emunType.Shape.Ellipse:
                    this.OnPaintBackground(pea);
                    switch (enmState)
                    {
                        case ControlState.Normal:
                            if (this.Enabled)
                            {
                                OnDrawEllipseButton(pea.Graphics);
                            }
                            else
                            {
                                OnDrawEllipseDisabled(pea.Graphics);
                            }
                            break;
                        case ControlState.Hover:
                            this.Cursor = Cursors.Hand;
                            OnDrawEllipseHover(pea.Graphics);
                            break;
                        case ControlState.Pressed:
                            OnDrawEllipsePressed(pea.Graphics);
                            break;
                    }
                    OnDrawTextAndImage(pea.Graphics);
                    if (m_showBorder) DrawEllipseBorder(pea.Graphics);
                    break;
                case emunType.Shape.BevelRectangle:
                    this.OnPaintBackground(pea);
                    switch (enmState)
                    {
                        case ControlState.Normal:
                            if (this.Enabled)
                            {
                                OnDrawRectangleButton(pea.Graphics);
                            }
                            else
                            {
                                OnDrawRectangleDisabled(pea.Graphics);
                            }
                            break;
                        case ControlState.Hover:
                            this.Cursor = Cursors.Hand;
                            OnDrawRectangleHover(pea.Graphics);
                            break;
                        case ControlState.Pressed:
                            OnDrawRectanglePressed(pea.Graphics);
                            break;
                    }
                    OnDrawTextAndImage(pea.Graphics);
                    if (m_showBorder) DrawRectangleBorder(pea.Graphics);
                    break;
            }
        }

        protected override void OnEnabledChanged(EventArgs ea)
        {
            base.OnEnabledChanged(ea);
            enmState = ControlState.Normal;
            this.Invalidate();
        }


        #region RectangleBevel
        private void OnDrawRectangleButton(Graphics g)
        {
            Rectangle rcBorder = this.BorderRectangle;
            Size size = new Size(rcBorder.Height / 8, rcBorder.Height / 8);

            LinearGradientBrush brushBackground = null;
            switch (m_colorSchema)
            {
                case emunType.ColorSchema.Default:
                    brushBackground = new LinearGradientBrush(rcBorder, clrBackground2, clrBackground1,
                        LinearGradientMode.ForwardDiagonal);
                    break;
                case emunType.ColorSchema.Blue:
                    brushBackground = new LinearGradientBrush(rcBorder, Color.FromArgb(248, 252, 253), Color.FromArgb(172, 171, 201), 
                        LinearGradientMode.ForwardDiagonal);
                    break;
                case emunType.ColorSchema.OliveGreen:
                    brushBackground = new LinearGradientBrush(rcBorder, Color.FromArgb(250, 250, 240), Color.FromArgb(235, 220, 190), 
                        LinearGradientMode.ForwardDiagonal);
                    break;
                case emunType.ColorSchema.Silver:
                    brushBackground = new LinearGradientBrush(rcBorder, Color.FromArgb(253, 253, 253), Color.FromArgb(205, 205, 205),
                        LinearGradientMode.ForwardDiagonal);
                    break;
            }

            Point[] points = new Point[6];
            points[0] = new Point(rcBorder.Left + size.Width, rcBorder.Top);
            points[1] = new Point(rcBorder.Right, rcBorder.Top);
            points[2] = new Point(rcBorder.Right, rcBorder.Bottom - size.Height);
            points[3] = new Point(rcBorder.Right - size.Width, rcBorder.Bottom);
            points[4] = new Point(rcBorder.Left, rcBorder.Bottom);
            points[5] = new Point(rcBorder.Left, rcBorder.Top + size.Height);
            g.FillPolygon(brushBackground, points);

            brushBackground.Dispose();
        }

        private void OnDrawRectangleHover(Graphics g)
        {
            Rectangle rcBorder = this.BorderRectangle;
            LinearGradientBrush brushSide = new LinearGradientBrush(
                rcBorder, Color.FromArgb(254, 221, 149), Color.FromArgb(249, 180, 53),
                LinearGradientMode.Vertical);

            Size size = new Size(rcBorder.Height / 8, rcBorder.Height / 8);
            //g.FillRectangle(brushBackground, rcBorder);
            Point[] points = new Point[6];
            points[0] = new Point(rcBorder.Left + size.Width, rcBorder.Top);
            points[1] = new Point(rcBorder.Right, rcBorder.Top);
            points[2] = new Point(rcBorder.Right, rcBorder.Bottom - size.Height);
            points[3] = new Point(rcBorder.Right - size.Width, rcBorder.Bottom);
            points[4] = new Point(rcBorder.Left, rcBorder.Bottom);
            points[5] = new Point(rcBorder.Left, rcBorder.Top + size.Height);

            g.FillPolygon(brushSide, points);

            brushSide.Dispose();


        }

        private void OnDrawRectanglePressed(Graphics g)
        {
            Rectangle rcBorder = this.BorderRectangle;

            SolidBrush brushBackground = new SolidBrush(Color.FromArgb(131, 144, 179));
            Size size = new Size(rcBorder.Height / 8, rcBorder.Height / 8);
            Point[] points = new Point[6];
            points[0] = new Point(rcBorder.Left + size.Width, rcBorder.Top);
            points[1] = new Point(rcBorder.Right, rcBorder.Top);
            points[2] = new Point(rcBorder.Right, rcBorder.Bottom - size.Height);
            points[3] = new Point(rcBorder.Right - size.Width, rcBorder.Bottom);
            points[4] = new Point(rcBorder.Left, rcBorder.Bottom);
            points[5] = new Point(rcBorder.Left, rcBorder.Top + size.Height);

            g.FillPolygon(brushBackground, points);
            brushBackground.Dispose();
        }

        private void OnDrawRectangleDisabled(Graphics g)
        {
            Rectangle rcBorder = this.BorderRectangle;

            SolidBrush brushBackground = new SolidBrush(Color.FromArgb(245, 244, 234));
            Size size = new Size(rcBorder.Height / 8, rcBorder.Height / 8);
            Point[] points = new Point[6];
            points[0] = new Point(rcBorder.Left + size.Width, rcBorder.Top);
            points[1] = new Point(rcBorder.Right, rcBorder.Top);
            points[2] = new Point(rcBorder.Right, rcBorder.Bottom - size.Height);
            points[3] = new Point(rcBorder.Right - size.Width, rcBorder.Bottom);
            points[4] = new Point(rcBorder.Left, rcBorder.Bottom);
            points[5] = new Point(rcBorder.Left, rcBorder.Top + size.Height);

            g.FillPolygon(brushBackground, points);
            brushBackground.Dispose();
        }
        #endregion

        #region Ellipse
        private void OnDrawEllipseButton(Graphics g)
        {
            Rectangle rcBorder = this.BorderRectangle;
            Size size = new Size(rcBorder.Height / 8, rcBorder.Height / 8);

            LinearGradientBrush brushBackground = null;
            switch (m_colorSchema)
            {
                case emunType.ColorSchema.Default:
                    brushBackground = new LinearGradientBrush(rcBorder, clrBackground2, clrBackground1,
                        LinearGradientMode.BackwardDiagonal);
                    break;
                case emunType.ColorSchema.Blue:
                    brushBackground = new LinearGradientBrush(rcBorder, Color.FromArgb(248, 252, 253), Color.FromArgb(172, 171, 201), LinearGradientMode.BackwardDiagonal);
                    break;
                case emunType.ColorSchema.OliveGreen:
                    brushBackground = new LinearGradientBrush(rcBorder, Color.FromArgb(250, 250, 240), Color.FromArgb(235, 220, 190), LinearGradientMode.BackwardDiagonal);
                    break;
                case emunType.ColorSchema.Silver:
                    brushBackground = new LinearGradientBrush(rcBorder, Color.FromArgb(253, 253, 253), Color.FromArgb(205, 205, 205),
                        LinearGradientMode.BackwardDiagonal);
                    break;
            }

            g.FillEllipse(brushBackground, rcBorder);
            brushBackground.Dispose();
        }

        private void OnDrawEllipseHover(Graphics g)
        {
            Rectangle rcBorder = this.BorderRectangle;
            LinearGradientBrush brushSide = new LinearGradientBrush(
                rcBorder, Color.FromArgb(254, 221, 149), Color.FromArgb(249, 180, 53),
                LinearGradientMode.Vertical);

            Size size = new Size(rcBorder.Height / 8, rcBorder.Height / 8);
            //g.FillRectangle(brushBackground, rcBorder);
            g.FillEllipse(brushSide, rcBorder);

            brushSide.Dispose();
        }

        private void OnDrawEllipsePressed(Graphics g)
        {
            Rectangle rcBorder = this.BorderRectangle;

            SolidBrush brushBackground = new SolidBrush(Color.FromArgb(131, 144, 179));
            Size size = new Size(rcBorder.Height / 8, rcBorder.Height / 8);
            g.FillEllipse(brushBackground, rcBorder);
            brushBackground.Dispose();
        }

        private void OnDrawEllipseDisabled(Graphics g)
        {
            Rectangle rcBorder = this.BorderRectangle;

            SolidBrush brushBackground = new SolidBrush(Color.FromArgb(245, 244, 234));
            Size size = new Size(rcBorder.Height / 8, rcBorder.Height / 8);
            g.FillEllipse(brushBackground, rcBorder);
            brushBackground.Dispose();
        }
        #endregion

        private void OnDrawTextAndImage(Graphics g)
        {
            SolidBrush brushText;
            Font font = null;
            if ((enmState == ControlState.Hover || enmState == ControlState.Pressed) && m_Shape == emunType.Shape.Transparent)
            {
                font = new Font(this.Font, this.Font.Style | FontStyle.Underline);
            }
            else
            {
                font = this.Font;
            }

            if (Enabled)
                brushText = new SolidBrush(ForeColor);
            else
                brushText = new SolidBrush(ControlPaint.DisabledForeColor);

            StringFormat sf = ControlPaint.GetStringFormat(this.TextAlign);
            sf.HotkeyPrefix = System.Drawing.Text.HotkeyPrefix.Show;

            if (this.Image != null)
            {
                Rectangle rc = new Rectangle();
                Point ImagePoint = new Point(6, 4);
                switch (this.ImageAlign)
                {
                    case ContentAlignment.MiddleRight:
                        {
                            rc.Width = this.ClientRectangle.Width - this.Image.Width - 8;
                            rc.Height = this.ClientRectangle.Height;
                            rc.X = 0;
                            rc.Y = 0;
                            ImagePoint.X = rc.Width;
                            ImagePoint.Y = this.ClientRectangle.Height / 2 - Image.Height / 2;
                            break;
                        }
                    case ContentAlignment.TopCenter:
                        {
                            ImagePoint.Y = 2;
                            ImagePoint.X = (this.ClientRectangle.Width - this.Image.Width) / 2;
                            rc.Width = this.ClientRectangle.Width;
                            rc.Height = this.ClientRectangle.Height - this.Image.Height - 4;
                            rc.X = this.ClientRectangle.X;
                            rc.Y = this.Image.Height;
                            break;
                        }
                    case ContentAlignment.MiddleCenter:
                        { // no text in this alignment
                            ImagePoint.X = (this.ClientRectangle.Width - this.Image.Width) / 2;
                            ImagePoint.Y = (this.ClientRectangle.Height - this.Image.Height) / 2;
                            rc.Width = 0;
                            rc.Height = 0;
                            rc.X = this.ClientRectangle.Width;
                            rc.Y = this.ClientRectangle.Height;
                            break;
                        }
                    default:
                        {
                            ImagePoint.X = 6;
                            ImagePoint.Y = this.ClientRectangle.Height / 2 - Image.Height / 2;
                            rc.Width = this.ClientRectangle.Width - this.Image.Width;
                            rc.Height = this.ClientRectangle.Height;
                            rc.X = this.Image.Width;
                            rc.Y = 0;
                            break;
                        }
                }
                ImagePoint.X += locPoint.X;
                ImagePoint.Y += locPoint.Y;
                if (this.Enabled)
                    g.DrawImage(this.Image, ImagePoint);
                else
                    System.Windows.Forms.ControlPaint.DrawImageDisabled(g, this.Image, locPoint.X, locPoint.Y, this.BackColor);
                g.DrawImage(this.Image, ImagePoint);

                if (ContentAlignment.MiddleCenter != this.ImageAlign)
                    g.DrawString(
                        this.Text,
                        font,
                        brushText,
                        rc,
                        sf);
            }
            else
                g.DrawString(
                    this.Text,
                    font,
                    brushText,
                    this.ClientRectangle,
                    sf);

            brushText.Dispose();
            sf.Dispose();
        }

        /// <summary>
        /// Draws the dark blue border of the XpButton object.
        /// </summary>
        /// <param name="g">The System.Drawing.Graphics object to be used to paint the border.</param>
        private void DrawRectangleBorder(Graphics g)
        {
            Pen penBorder = new Pen(clrBorder);
            Rectangle rect = new Rectangle(this.BorderRectangle.Left, this.BorderRectangle.Top, this.BorderRectangle.Width, this.BorderRectangle.Height);

            ControlPaint.DrawRoundedRectangle(g, penBorder, rect,
                sizeBorderPixelIndent);
            penBorder.Dispose();
        }

        private void DrawEllipseBorder(Graphics g)
        {
            Pen penBorder = new Pen(clrBorder);
            Rectangle rect = new Rectangle(this.BorderRectangle.Left, this.BorderRectangle.Top, this.BorderRectangle.Width, this.BorderRectangle.Height);

            SmoothingMode oldSmoothingMode = g.SmoothingMode;
            g.SmoothingMode = SmoothingMode.AntiAlias;

            g.DrawEllipse(penBorder, rect);

            g.SmoothingMode = oldSmoothingMode;
            penBorder.Dispose();
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                    components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            components = new System.ComponentModel.Container();
        }
        #endregion
    }
    public class emunType
    {
        public enum ColorSchema { Default, Blue, OliveGreen, Silver }
        public enum Shape { Default, BevelRectangle, Ellipse, Transparent }
    }
}
